#!/usr/bin/python
# -*- coding: GB2312 -*-

# twisted imports
from OpenSSL import SSL
from twisted.internet import defer
from twisted.internet import protocol
from twisted.internet import reactor
from twisted.internet import ssl
from twisted.internet import task
from twisted.internet import threads
from twisted.words.protocols import irc
import bsddb
import httplib
import pickle
import re
import string
import subprocess
import sys
import urlparse
import socket
import time

# system imports

__VERSION__ = '0.2'

re_whois = re.compile( r"""^\^[Ww][Hh][Oo][Ii][Ss]\b""" )
re_url = re.compile( r'''^(http|ftp|https)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&amp;%\$\-]+)*@)?((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.[a-zA-Z]{2,4})(\:[0-9]+)?(/[^/][a-zA-Z0-9\.\,\?\'\\/\+&amp;%\$#\=~_\-@]*)*$''' )

class LinkDataBinding:
    '''
    link bot data
    link_bot_data = {name0:[url, size, last_size, updatetime, last_updatetime, last_status, last_headers, user], \
                     name1:[url, size, last_size, updatetime, last_updatetime, last_status, last_headers, user]   }
    link_bot_data = {}
    '''
    
    def __init__( self ):
        '''
        read linkbot data from file
        '''
        self.linkbot_data = bsddb.btopen( 'linkbot.db', 'c' )
        
    def zip_data( self, d ):
        return '|||SPACE|||'.join( d )
    
    def unzip_data( self, d ):
        return d.split( '|||SPACE|||' ) 
        
    def add_item( self, name, data ):
        if self.linkbot_data.has_key( name ):
            return False
        else:
            self.linkbot_data[name] = self.zip_data( data )
            self.linkbot_data.sync()
            return True
    
    def update_item( self, name, data ):
        if self.linkbot_data.has_key( name ):
            self.linkbot_data[name] = self.zip_data( data )
            self.linkbot_data.sync()
            return True
        else:
            return False
        
    def del_item( self, name ):
        try:
            del self.linkbot_data[name]
            self.linkbot_data.sync()
            return True
        except KeyError:
            return False
        
    def get_item_data( self, name ):
        if self.linkbot_data.has_key( name ):
            return self.unzip_data( self.linkbot_data[name] )
        else:
            return False
        
    def get_all_item_name( self ):
        return self.linkbot_data.keys()
    
    def get_all_item_data( self ):
        return self.linkbot_data
    
    def sync_to_disk( self ):
        pass

def split_url( u ):
    _u = urlparse.urlsplit( u )
    return '%s' % _u[1], '%s?%s%s' % _u[2:]

def pheader( h ):
    _s = ''
    for x in h:
        _s += '%s: %s\r\n' % ( x[0].title(), x[1] )
    return _s

#===============================================================================
# def running_wget_command(u=''):
#    '''
#    run wget command ,and return http protocal header or ftp protocal file size
#    @param u:
#    '''
#    PIPE = subprocess.PIPE
#    #p = subprocess.Popen('wget -S --spider http://www.google.com', shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
#    #(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
#    
#    p = subprocess.Popen( 'wget -S --spider http://google.com', shell=True, stdout=PIPE, stderr=PIPE)
#    ( child_stdin, child_stdout, child_stderr ) = ( p.stdin, p.stdout, p.stderr )
#    for x in child_stderr.readlines():
#        print x
#===============================================================================

def read_ftp_header_fill_linkbot_data( n ):
    pass

def read_http_header_fill_linkbot_data( n ):
    '''
     read http header and fill it to linkbot data
     @param n:
     @param d:
    '''
    i_url, i_size, i_lsize, i_modified, i_lmodified, i_status, i_lstatus, i_oheader, i_loheader, i_user, i_guess = linkbot_data_binding.get_item_data( n )
    _i_host, _i_path = split_url( i_url )
    conn = httplib.HTTPConnection( _i_host )
    #conn.sock.set_timeout(15)
    try:
        conn.request( "GET", _i_path )
        r1 = conn.getresponse()
    except socket.error:
        i_url, i_size, i_lsize, i_modified, i_lmodified, i_status, i_lstatus, i_oheader, i_loheader, i_user, i_guess = \
            i_url, 'ERROR', 'ERROR', 'ERROR', 'ERROR', 'ERROR', 'ERROR', 'ERROR', 'ERROR', i_user, 'ERROR'
        linkbot_data_binding.update_item( n, [i_url, i_size, i_lsize, i_modified, i_lmodified, i_status, i_lstatus, i_oheader, i_loheader, i_user, i_guess] )
        conn.close()
        return i_url, i_size, i_lsize, i_modified, i_lmodified, i_status, i_lstatus, i_oheader, i_loheader, i_user, i_guess
        
    #url
    i_url = i_url
    
    # SIZE
    i_lsize = r1.getheader( 'content-length' )
    if i_size == 'UNKNOW':
        i_size = r1.getheader( 'content-length' )
    i_osize = i_size
    if i_osize == i_lsize:
        pass
    elif i_osize != i_lsize:
        i_size = r1.getheader( 'content-length' )
    
    # modified
    i_lmodified = r1.getheader( 'last-modified' )
    #i_modified
    if i_modified == 'UNKNOW':
        i_modified = r1.getheader( 'last-modified' )
    i_omodified = i_modified
    if i_omodified == i_lmodified:
        pass
    elif i_omodified != i_lmodified:
        i_modified = r1.getheader( 'last-modified' )
      
    #i_lstatus
    i_lstatus = r1.reason
    if i_status == 'UNKNOW':
        i_status = r1.reason
    i_ostatus = i_status
    if i_ostatus == i_lstatus:
        pass
    elif i_ostatus != i_lstatus:
        i_status = r1.reason

    #header
    i_loheader = pheader( r1.getheaders() )
    if i_oheader == 'UNKNOW':
        i_oheader = pheader( r1.getheaders() )
    i_ooheader = i_oheader
    if i_ooheader == i_loheader:
        pass
    elif i_ooheader != i_loheader:
        i_oheader = i_loheader
         
    #i_user
    i_user = i_user
     
    #i_guess
    if i_ostatus != i_lstatus or i_osize != i_lsize or i_omodified != i_lmodified:
        i_guess = 'YES'
    else:
        i_guess = 'NO'
     
    conn.close()
     
    linkbot_data_binding.update_item( n, [i_url, i_size, i_lsize, i_modified, i_lmodified, i_status, i_lstatus, i_oheader, i_loheader, i_user, i_guess] )
     
    return i_url, i_osize, i_lsize, i_omodified, i_lmodified, i_status, i_lstatus, i_oheader, i_loheader, i_user, i_guess
    
def check_link_one( i ):
    start_time = time.time()
    i_url, i_size, i_lsize, i_modified, i_lmodified, i_status, i_lstatus, i_oheader, i_loheader, i_user, i_guess = read_http_header_fill_linkbot_data( i )
    s = r'''05#URL: %s
05#Size: %s
05#Last_Size: %s
05#Modified_Time: %s
05#Last_Modified_Time: %s
05#Status: %s
05#Last_status: %s
05#Original Http Header===========================================================
%s
05#Original Http Header END=======================================================
05#Last Original Http Header======================================================
%s
05#Last Original Http Header END==================================================
05#User: %s
05#Guess_Modified?: %s
05#END, Running Time: %s S
''' % ( i_url, i_size, i_lsize, i_modified, i_lmodified, i_status, i_lstatus, i_oheader, i_loheader, i_user, i_guess, str(time.time()-start_time) )
    return s

def check_link_all():
    start_time = time.time()
    item_list = linkbot_data_binding.get_all_item_name()
    s = ''
    for x in item_list:
        i_url, i_size, i_lsize, i_modified, i_lmodified, i_status, i_lstatus, i_oheader, i_loheader, i_user, i_guess = read_http_header_fill_linkbot_data( x )
        s += '''05#Name: %s URL: %s Size: %s Guess_modified: %s \r\n''' % ( x, i_url, i_lsize, i_guess )
    s += '''05#Check all Link Done... Running Time: %s S''' % str(time.time()-start_time)
    return s
    
class Bot( irc.IRCClient ):
    """IRC bot."""
    _pendingQuit = None
    
    def __init__( self ):
        self.nickname = bot_nick
        self.password = server_password
        self._pending = []
    
    def _makeCommand( self, name, additional=None, unknownHandler=None ):
        self._pending.append( ( name, defer.Deferred(), additional, unknownHandler ) )
        return self._pending[-1][1]

    def connectionMade( self ):
        irc.IRCClient.connectionMade( self )

    def connectionLost( self, reason ):
        irc.IRCClient.connectionLost( self, reason )

    # callbacks for events

    def signedOn( self ):
        """Called when bot has succesfully signed on to server."""
        self.msg( 'NickServ', ' IDENTIFY %s' % bot_nick_password )
        self.oper()
        for self.channel, self.channel_key in self.factory.channel_list.iteritems():
            self.join( self.channel, self.channel_key )
        
        global LOOP_ID
        LOOP_ID = 0
        task_looping = task.LoopingCall(self.task_looping)
        task_looping.start( LOOP_TIME )

#    def joined( self, channel ):
#        #self.say( channel, self.factory.botJoin() )
#        pass

#    def whois( self, user ):
#        """Retrieve information about the specified user.
#        
#        @type user: C{str}
#        @param user: The user about whom to retrieve information.
#        
#        @rtype: C{Deferred} of C{dict} mapping information tags to
#        received information.  The items of this dict are as follows:
#        
#            'user':      (ident, hostmask, real name)
#            'server':    (server, server info)
#            'operator':  True
#            'idle':      idle time, in seconds, as an integer
#            'channels':  list of strings indicating the channels to which
#                            the user belongs
#        
#        Other keys may exist if the server responds with non-standard
#        information.
#        """
#        self.say( report_channel, '# Staring query user [ %s ], Pleast wait...' % user )
#        self.sendLine( "WHOIS " + user )
#        return self._makeCommand( "WHOIS", {}, unknownHandler=self._userhostHandler )
#    
#    def userhost( self, user ):
#        self.sendLine( "USERHOST " + user )
#        return self._makeCommand( "USERHOST", {}, unknownHandler=self._userhostHandler )
    
    def oper( self ):
        self.sendLine( "OPER fla itisagoodday" )
    
    def _getHandler( self ):
        if not self._pending:
            raise ValueError( "No current command" )
        f = self._pending[0][3]
        if f is None:
            raise ValueError( "Current unknown-handler is None" )
        return f

    def _getAdd( self, command=None, possible=() ):
        if not self._pending:
            raise ValueError( "No current command" )
        if command is not None:
            if self._pending[0][0] == command:
                return self._pending[0][2]
            else:
                raise ValueError( "Current command not %r" % ( command, ) )
        else:
            if self._pending[0][0] in possible:
                return self._pending[0][2]
            else:
                raise ValueError( "Current command not in %r" % ( command, ) )
               
    def _getDeferred( self, command=None, possible=() ):
        # We can prevent offset errors induced by the receipt of unexpected
        # messages in addition to those we do expect, but I see no way to
        # prevent those induced by the omission of expected messages or the
        # receipt of expected messages in an unexpected order (that is, any
        # order other than that in which we send the associated commands). 
        # Therefore, if a server fails to respond in the manner which we
        # expected, client code using this class will likely become hung and
        # remain so forever.
        if not self._pending:
            raise ValueError( "No commands pending" )
        if command is not None:
            if self._pending[0][0] == command:
                return self._pending.pop( 0 )[1]
            else:
                raise ValueError( "Next command is not %r" % ( command, ) )
        else:
            if self._pending[0][0] in possible:
                return self._pending.pop( 0 )[1]
            else:
                raise ValueError( "Next command not in %r" % ( command, ) )

    def _callback( self, command=None, possible=(), args=None, additional=False ):
        if additional:
            try:
                args = self._getAdd( command )
            except ValueError:
                print "Unexpected callback for %r" % ( command, )
                return
        try:
            d = self._getDeferred( command=command, possible=possible )
        except ValueError, e:
            print "Unexpected callback: %s" % ( e, )
        else:
            d.callback( args )

    def _errback( self, command=None, possible=(), failure=None ):
        try:
            d = self._getDeferred( command=command, possible=possible )
        except ValueError, e:
            print "Unexpected errback: %s" % ( e, )
        else:
            d.errback( failure )

#    def _whoisHandler( self, prefix, command, params ):
#        try:
#            command = int( command )
#        except ValueError:
#            pass
#        self._getAdd( "WHOIS" ).setdefault( command, [] ).append( params )
#        
#    def _userhostHandler( self, prefix, command, params ):
#        try:
#            command = int( command )
#        except ValueError:
#            pass
#        self._getAdd( "USERHOST" ).setdefault( command, [] ).append( params )
#    
#    def irc_RPL_WHOISUSER( self, prefix, params ):
#        #self._getAdd("WHOIS")['user'] = params[2], params[3], params[5]
#        #print prefix, params, 'RPL_WHOISUSER'
#        self.say( report_channel, 'User %s is %s@%s' % ( params[1], params[2], params[3] ) )
#    
#    def irc_RPL_WHOISSERVER( self, prefix, params ):
#        #self._getAdd("WHOIS")['server'] = params[2], params[3]
#        #print prefix, params, 'WHOISSERVER'
#        pass
#    
#    def irc_RPL_WHOISOPERATOR( self, prefix, params ):
#        #self._getAdd("WHOIS")['operator'] = True
#        #print prefix, params, 'WHOISOPERATOR'
#        self.say( report_channel, 'User is %s' % params[2] )
#    
#    def irc_RPL_WHOISIDLE( self, prefix, params ):
#        #self._getAdd("WHOIS")['idle'] = int(params[2])
#        #print prefix, params, 'WHOISIDLE'
#        pass
#    
#    def irc_RPL_WHOISCHANNELS( self, prefix, params ):
#        #self._getAdd("WHOIS").setdefault('channels', []).extend(params[2].split())
#        #print prefix, params, 'WHOISCHANNELS'
#        self.say( report_channel, 'User %s on Channel %s' % ( params[1], params[2] ) )
#    
#    def irc_RPL_ENDOFWHOIS( self, prefix, params ):
#        #self._callback("WHOIS", additional=True)
#        #print prefix, params, 'ENDOFWHOIS'
#        #self.say( report_channel, '# End of /WHOIS list.' )
#        pass
#    
#    def irc_ERR_NOSUCHNICK( self, prefix, params ):
#        #self._errback(possible=("WHOIS",), failure=NoSuchNickname())
#        #print prefix, params, 'ERR_NOSUCHNICK'
#        self.say( report_channel, 'User %s No such nick/channel' % params[1] )
#        self.say( report_channel, '# End of /WHOIS list.' )
#        
#    def irc_RPL_USERHOST( self, prefix, params ):
#        #self._errback(possible=("WHOIS",), failure=NoSuchNickname())
#        #print prefix, params, 'RPL_USERHOST'
#        try:
#            user_name, user_ip = params[1].split('@')
#            self.say(report_channel,'User %s is connecting from %s' % (user_name,user_ip))
#            self.say( report_channel, '# End of /WHOIS list.' )
#        except :
#            pass
#         
#    def irc_ERR_NEEDMOREPARAMS( self, prefix, params ):
#        #self._errback(possible=("WHOIS",), failure=NoSuchNickname())
#        #print prefix, params, 'ERR_NEEDMOREPARAMS'
#        pass

    def saymanay( self, s ):
        for x in s.splitlines():
            self.say( self.channel, x )
            
    def report_all( self, d ):
        l = len(d)
        s = r'''07'''
        for iname, idata in d.iteritems():
            res_data = linkbot_data_binding.unzip_data( idata )
            s += '''07#Name: %s URL: %s Guess_modified: %s \r\n''' % ( iname, res_data[0], res_data[10] )
            
        s += r'''07#END, [ %d ] item listed''' % l
        return s
    
    def report_one( self, n, d ):
        '''link_bot_data = {name0:[url, size, last_size, updatetime, last_updatetime, last_status, last_headers, user], \
                     name1:[url, size, last_size, updatetime, last_updatetime, last_status, last_headers, user]   }'''
        s = r'''07#Name: %s
07#URL: %s
07#Size: %s
07#Last_Size: %s
07#Modified_Time: %s
07#Last_Modified_Time: %s
07#Status: %s
07#Last_status: %s
07#Guess_Modified?: %s
07#END''' % ( n, d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[10] )
        return s
    
    def check_all_report( self, res ):
        '''
        report check all item
        '''
        #self.say( self.channel, res )
        self.saymanay( res )
        #print res
    
    def check_one_report( self, res ):
        '''
        report check one item
        '''
        self.saymanay( res )
    
    def do_h( self, *argv ):
        
        self.saymanay( '''05#ZWT LinkBot v0.1
05^link h                : Print human-readable names for services
05^link li %name         : List link item info, if not give %name will list all link item
05^link ai %name %url    : Add link item
05^link di %name         : Delete link item
05^link ck %name         : Check link item, if not give %name will check all link item
05# end of ZWT LinkBot help
''' )
    
    def do_li( self, *argv ):
        a = argv[0]
        if len( a ) < 1:
            self.say( self.channel, '''07#List all item''' )
            res = linkbot_data_binding.get_all_item_data()
            self.saymanay( self.report_all( res ) )
        else:
            self.say( self.channel, '''07#List item: %s''' % a[0] )
            res = linkbot_data_binding.get_item_data( a[0] )
            if res:
                self.saymanay( self.report_one( a[0], res ) )
            else:
                self.say( self.channel, '''04#List item: %s FALSE, not found item in my database''' % a[0] )
        
    def do_ai( self, *argv ):
        '''link_bot_data = {name0:[url, size, last_size, updatetime, last_updatetime, last_status, last_headers, user], \
                     name1:[url, size, last_size, updatetime, last_updatetime, last_status, last_headers, user]   }'''
        a = argv[0]
        if len( a ) < 2:
            self.say( self.channel, '''04Command Error %s ...plz use '^link h' command''' % self.m )
        else:
            if re_url.match( a[1] ):
                res = linkbot_data_binding.add_item( a[0], [a[1], 'UNKNOW', 'UNKNOW', 'UNKNOW', 'UNKNOW', 'UNKNOW', 'UNKNOW', 'UNKNOW', 'UNKNOW', self.user, 'UNKNOW'] )
            else:
                self.say( self.channel, '''05#user: %s, Add link item: %s, url: %s, FALSE, may be name dupe,or not vaild url''' % ( self.user, a[0], a[1] ) )
                return
            if res:
                self.say( self.channel, '''05#User: %s, Add link item: %s, url: %s, SUCCESS''' % ( self.user, a[0], a[1] ) )
            else:
                self.say( self.channel, '''05#User: %s, Add link item: %s, url: %s, FALSE, may be name dupe,or not vaild url''' % ( self.user, a[0], a[1] ) )
        
    def do_ei( self, *argv ):
        a = argv[0]
        self.say( self.channel, '''05#Add link item: %s, url:%s''' % ( a[0], a[1] ) )
    
    def do_di( self, *argv ):
        a = argv[0]
        if len( a ) < 1:
            self.say( self.channel, '''04Command Error %s ...plz use '^link h' command''' % self.m )
        else:
            res = linkbot_data_binding.del_item( a[0] )
            if res:
                self.say( self.channel, '''05#Delete link item: %s SUCCESS''' % a[0] )
            else:
                self.say( self.channel, '''04#Delete link item: %s FALSE, not found item''' % a[0] )
                
    def do_dl( self, *argv ):
        a = argv[0]
        if len( a ) < 1:
            self.say( self.channel, '''04#Command Error %s ...plz use '^link h' command''' % self.m )
        else:
            res = self.factroy.linkbot_data.get_item_data( a[0] )
            if res:
                self.say( self.channel, '''05#Start Download %s ...plz wait''' % self.m )
            else:
                self.say( self.channel, '''05#Can not download item: %s, plz check''' % a[0] )
        
    def do_ck( self, *argv ):
        a = argv[0]
        if len( a ) < 1:
            self.say( self.channel, '''05#Check all link item, plz wait, when i finished job, I will report result to this channel''' )
            d = threads.deferToThread( check_link_all )
            d.addCallback( self.check_all_report )
        else:
            self.say( self.channel, '''05#Check link item: %s, plz wait, when i finished job, I will report result to this channel''' % a[0] )
            d = threads.deferToThread( check_link_one, a[0] )
            d.addCallback( self.check_one_report )
            
#===============================================================================
#    def do_task_looping(self):
#        d = defer.Deferred()
#        reactor.callLater(1, d.callback, check_link_all)
#        return d
##===============================================================================
    
    def task_looping(self):
#        d = self.do_task_looping()
#        d.addCallback(self.check_all_report)
        global LOOP_ID
        LOOP_ID = LOOP_ID + 1
        self.say( self.channel, '''05#Auto Check all link item, loop id: %d''' % LOOP_ID )
        LOOP_ID
        d = threads.deferToThread( check_link_all )
        d.addCallback( self.check_all_report )

    def action( self, user, channel, msg ):
        """This will get called when the bot sees someone do an action."""
        user = user.split( '!', 1 )[0]
        return user
    
    def _clean_space( self, d ):
        '''
        fix command header or foot space
        @param d:
        '''
        _t = []
        for x in d:
            if x == '':
                pass
            else:
                _t.append( x.strip() )
        return _t
    
    def privmsg( self, user, channel, msg ):
        """This will get called when the bot receives a message."""
        user = user.split( '!', 1 )[0]
        self.user = user
        self.channel = channel
        self.m = msg.strip()
        if self.m.startswith( '^link' ):
            self.c = self._clean_space( self.m.split( ' ' ) )
            if len( self.c ) == 1:
                self.do_h()
                return
            if hasattr( self, 'do_'+self.c[1] ):
                self.parm = self.c[2:]
                getattr( self, 'do_'+self.c[1], self.do_h )( self.parm )
            else:
                self.say( self.channel, '''04Unknow command %s ...plz use '^link h' command''' % self.m )
            
    def action( self, user, channel, msg ):
        """This will get called when the bot sees someone do an action."""
        user = user.split( '!', 1 )[0]
        return user
        
#    def modeChanged( self, user, channel, set, modes, args ):
#        pass
        
    def kickedFrom( self, channel, kicker, message ):
        self.signedOn()
        self.say( channel, 'Why me??' )
        
    def userJoined( self, user, channel ):
        self.mode( channel, set='+', modes='o', limit=None, user=user, mask=None )
        self.say( report_channel, 'User:%s Got OP in Channel:%s' % ( user, channel ) )
        
#    def irc_NICK( self, prefix, params ):
#        """Called when an IRC user changes their nickname."""
#        old_nick = prefix.split( '!' )[0]
#        new_nick = params[0]
    
class BotFactory( protocol.ClientFactory ):
    """A factory for linkBots.
        """
    protocol = Bot

    def __init__( self, channel_list ):
        self.channel_list = channel_list
        self.conn_times = 0
        self.linkbot_data = LinkDataBinding()
        
    def botJoin( self ):
        join_msg = """Hello all, I'm auto link Bot."""
        return join_msg
        
    def clientConnectionLost( self, connector, reason ):
        """If we get disconnected, reconnect to server."""
        self.conn_times += 1
        if self.conn_times <= 5:
            time.sleep( 3 )
            print 'connect %d times' % self.conn_times
            connector.connect()
        else:
            print "connection failed:", reason
            reactor.stop()

    def clientConnectionFailed( self, connector, reason ):
        print "connection failed:", reason
        reactor.stop()
        

if __name__ == '__main__':
    """
    config in here {channel:channel_password,channel1:channel_passwod1}
    """
    global channel_list
    global bot_nick
    global bot_nick_password
    global server_password
    global report_channel
    global linkbot_data_binding
    global LOOP_TIME

    LOOP_TIME = 60 *60 # sec
    
    linkbot_data_binding = LinkDataBinding()
    
    report_channel = 'chatroom'
    
    channel_list = {#'zservices':'letmein', \
                        #'zwt':'wearebee', \
                        #'zwtiso':'BackInBlack', \
                        #'ddu':'ggstudy', \
                        #'dduiso':'ddu', \
                        #'crack':'zKu2vcJL', \
                        #'geeker':'qt6348wje34dsj3', \
                        #'tiantian':'mn56mn349fdw', \
                        #'preinfo':'das8u342093421', \
                        #'pre':'&f34fd324$3fd', \
                        #'blah':'l8j5b4b6l1', \
                        'chatroom':'miniworld', \
                        #'linkbot':'lalala', \
                        #'nage':'n3wagE', \
                        #'race':'pprace', \
                        #'pre.race':'raceinfo', \
                        #'prerace':'pre', \
                        #'ZCORE':'9A8juaiwuk8', \
                        #'deluxe':'', \
                        #'deluxe-spam':'', \
                        #'test':'', \
                        #'f-pre':'', \
                        #'frandre':''
                        }
    bot_nick = 'linkBOT'
    bot_nick_password = 's13c24'
    server_password = 'qetuoadgjl'              
    
    factory = BotFactory( channel_list )
    reactor.connectSSL( '202.108.12.48', 65432, factory, ssl.ClientContextFactory() )
    #run bot
    reactor.run()
